#include "straightline/slp.h"

#include <iostream>
#include <cstdio>

int max(int a, int b) { return a > b ? a : b; }

namespace A {
int A::CompoundStm::MaxArgs() const {
  int a = stm1 -> MaxArgs();
  int b = stm2 -> MaxArgs();
  return max(a,b);
}

Table *A::CompoundStm::Interp(Table *t) const {
  // TODO: put your code here (lab1).
  auto a = stm1 -> Interp(t);
  auto b = stm2 -> Interp(a);
  return b;
}

int A::AssignStm::MaxArgs() const {
  int a = exp -> MaxArgs();
  return a;
}

Table *A::AssignStm::Interp(Table *t) const {
  auto a = exp -> Interp(t);
  a -> t = a -> t -> Update(id,a->i);
  return a -> t;
}

int A::PrintStm::MaxArgs() const {
  int a = exps -> MaxArgs();
  return a;
}

Table *A::PrintStm::Interp(Table *t) const {
  auto a = exps -> Interpall(t);
  return a->t;
}

IntAndTable *IdExp::Interp(Table *t) const{
  return new IntAndTable(t->Lookup(id),t);
}

IntAndTable *NumExp::Interp(Table *t) const{
  return new IntAndTable(num,t);
}

IntAndTable *OpExp::Interp(Table *t) const{
  auto a = left -> Interp(t);
  auto b = right-> Interp(t);
  int c = 0;
  switch(oper){
    case A::PLUS: c = a->i + b->i; break;
    case A::MINUS:c = a->i - b->i; break;
    case A::TIMES:c = a->i * b->i; break;
    case A::DIV:  if(b -> i == 0) return new IntAndTable(0,t);
               else c = a->i / b->i; break;
    default: return new IntAndTable(0,t);
  }
  //delete a; delete b;
  return new IntAndTable(c,t);
}

int EseqExp::MaxArgs() const{
   int a = stm -> MaxArgs();
   int b = exp -> MaxArgs();
   return max(a, b+1);
}

IntAndTable *EseqExp::Interp(Table *t) const{
  auto a = stm -> Interp(t);
  auto b = exp -> Interp(a);
  return b;
}

IntAndTable *PairExpList::Interp(Table *t) const{
  auto a = exp -> Interp(t);
  auto b = tail-> Interp(a->t);
  //delete a;
  return b;
}

IntAndTable *PairExpList::Interpall(Table *t) const{
  auto a = exp -> Interp(t);
  printf("%d ",a->i);
  auto b = tail -> Interpall(a->t);
  return b;
}

IntAndTable *LastExpList::Interp(Table *t) const{
  return exp -> Interp(t);
}

IntAndTable *LastExpList::Interpall(Table *t) const{
  auto b = exp -> Interp(t);
  printf("%d\n",b->i);
  return b;
}

int Table::Lookup(const std::string &key) const {
  if (id == key) {
    return value;
  } else if (tail != nullptr) {
    return tail->Lookup(key);
  } else {
    assert(false);
  }
}

Table *Table::Update(const std::string &key, int val) const {
  return new Table(key, val, this);
}
}  // namespace A
